package ge.devfest.hackathon.gg;

import ge.devfest.hackathon.gg.json.JSONParser;
import ge.devfest.hackathon.gg.model.Activity;
import ge.devfest.hackathon.gg.model.Activity.Status;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;

public class ActivityFetcherService extends Service {

	public static final int FETCH_STATUS_OK = 0;
	public static final int FETCH_STATUS_IO_EXCEPTION = 1;
	public static final int FETCH_STATUS_JSON_EXCEPTION = 2;
	public static final int FETCH_STATUS_UNKNOWN_EXCEPTION = 3;
	
	private static final String TAG = "ActivityFetcherService";
	
	private String mUrl = "http://gardening.freelancer.ge/api/wine/";
	private JSONParser mParser = JSONParser.getInstance();

	private LocalBinder mLocalBinder = new LocalBinder();
	private boolean mRunning;
	private Handler mMainHandler = new Handler(Looper.getMainLooper());
	private ActivityFetcherListener mListener;
	
	@Override
	public IBinder onBind(Intent intent) {
		return mLocalBinder;
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		if (!mRunning) {
			mRunning = true;
			new Thread() {
				public void run() {
					doFetchActivities();
					mRunning = false;
					stopSelf();
				}
			}.start();
		}
		return super.onStartCommand(intent, flags, startId);
	}
	
	private void doFetchActivities() {
		List<Activity> activities = null;
		int errCode = FETCH_STATUS_OK;
		try {
			JSONArray array = getJSONArray();
			int n = array.length();
			activities = new ArrayList<Activity>(n);
			for (int i = 0; i < n; i++) {
				activities.add(parseActivity(getJSONObject(i, array)));
			}
		} catch (JSONException e) {
			errCode = FETCH_STATUS_JSON_EXCEPTION;
		} catch (IOException e) {
			errCode = FETCH_STATUS_JSON_EXCEPTION;
		} catch (Exception e) {
			errCode = FETCH_STATUS_UNKNOWN_EXCEPTION;
		}
		dispatchFetchComplete(errCode, activities);
	};

	private JSONObject getJSONObject(int i, JSONArray array) throws JSONException {
		try {
			return array.getJSONObject(i);
		} catch (JSONException e) {
			Log.e(TAG, "Unable to get json object at index: " + i + " from array: " + array, e);
			throw e;
		}
	}
	
	private JSONArray getJSONArray() throws JSONException, IOException {
		try {
			return mParser.parse(mUrl);
		} catch (JSONException e) {
			Log.e(TAG, "Unable to get JSONArray from url: " +  mUrl, e);
			throw e;
		} catch (IOException e) {
			Log.e(TAG, "Error while connecting to url: " + mUrl, e);
			throw e;
		}	
	}
	
	private Activity parseActivity(JSONObject jsonObj) throws JSONException {
		Activity activity = new Activity();
		activity.setId(getInt("LocationID", jsonObj));
		activity.setTitle(getString("Title", jsonObj));
		activity.setStatus(Status.values()[getInt("StatusID", jsonObj) - 1]);
		activity.setLatitude(getDouble("Latitude", jsonObj));
		activity.setLongitude(getDouble("Longitude", jsonObj));
		// activity.setImageUrl(null); TODO ask to levi to add imageUrl in webService
		return activity;
	}
	
	private String getString(String name, JSONObject jsonObj) throws JSONException {
		try {
			return jsonObj.getString(name);
		} catch (JSONException e) {
			Log.e(TAG, "Unable to get String: " + name + " from json: " + jsonObj, e);
			throw e;
		}
	}
	
	private int getInt(String name, JSONObject jsonObj) throws JSONException {
		try {
			return jsonObj.getInt(name);	
		} catch (JSONException e) {
			Log.e(TAG, "Unable to get int: " + name + " from json: " + jsonObj, e);
			throw e;
		}
	}
	
	private double getDouble(String name, JSONObject jsonObj) throws JSONException {
		try {
			return jsonObj.getDouble(name);
		} catch (JSONException e) {
			Log.e(TAG, "Unable to get double: " + name + " from json: " + jsonObj, e);
			throw e;
		}
	}
	
	private void dispatchFetchComplete(final int errCode, final List<Activity> activities) {
		mMainHandler.post(new Runnable() {
			
			@Override
			public void run() {
				ActivityFetcherListener l = mListener;
				if (l != null) {
					l.onFetchCompleted(errCode, activities);
				}
			}
		});
	}
	
	public void setActivityFetcherListener(ActivityFetcherListener l) {
		mListener = l;
	}
	
	class LocalBinder extends Binder {

		public ActivityFetcherService getService() {
			return ActivityFetcherService.this;
		}

	}

	public static interface ActivityFetcherListener {
		
		void onFetchCompleted(int errCode, List<Activity> activities);
	}
}
